package main

import (
	"fmt"
	"sync"
	"time"
)

/*
	PubSub系统

消息系统：实现发布-订阅模式
*/
type Message struct {
	Topic   string
	Content string
	Time    time.Time
}

type PubSub struct {
	subscribers map[string][]chan Message
	mu          sync.RWMutex
}

func NewPubSub() *PubSub {
	return &PubSub{
		subscribers: make(map[string][]chan Message),
	}
}

// 订阅主题
func (ps *PubSub) Subscribe(topic string) <-chan Message {
	ps.mu.Lock()
	defer ps.mu.Unlock()

	ch := make(chan Message, 10)
	ps.subscribers[topic] = append(ps.subscribers[topic], ch)

	return ch
}

// 发布消息
func (ps *PubSub) Publish(topic string, content string) {
	ps.mu.RLock()
	defer ps.mu.RUnlock()

	message := Message{
		Topic:   topic,
		Content: content,
		Time:    time.Now(),
	}

	for _, ch := range ps.subscribers[topic] {
		select {
		case ch <- message:
		default:
			fmt.Printf("Channel满，丢弃消息: %s\n", content)
		}
	}
}

func main() {
	ps := NewPubSub()

	// 订阅者1：订阅tech主题
	go func() {
		techChan := ps.Subscribe("tech")
		for msg := range techChan {
			fmt.Printf("[Tech订阅者] %s: %s\n", msg.Time.Format("15:04:05"), msg.Content)
		}
	}()

	// 订阅者2：订阅news主题
	go func() {
		newsChan := ps.Subscribe("news")
		for msg := range newsChan {
			fmt.Printf("[News订阅者] %s: %s\n", msg.Time.Format("15:04:05"), msg.Content)
		}
	}()

	// 订阅者3：同时订阅两个主题
	go func() {
		techChan := ps.Subscribe("tech")
		newsChan := ps.Subscribe("news")

		for {
			select {
			case msg := <-techChan:
				fmt.Printf("[多主题订阅者-Tech] %s\n", msg.Content)
			case msg := <-newsChan:
				fmt.Printf("[多主题订阅者-News] %s\n", msg.Content)
			}
		}
	}()

	// 发布消息
	fmt.Println("开始发布消息...")

	messages := []struct {
		topic   string
		content string
	}{
		{"tech", "Go 1.20 发布了!"},
		{"news", "今日天气晴朗"},
		{"tech", "Docker 新版本发布"},
		{"news", "股市大涨"},
		{"tech", "Kubernetes 安全更新"},
	}

	for _, msg := range messages {
		ps.Publish(msg.topic, msg.content)
		time.Sleep(500 * time.Millisecond)
	}

	// 等待消息处理
	time.Sleep(2 * time.Second)
	fmt.Println("演示结束")
}
